//@author A0096759E

package logic;

import storage.ScheduleEvent;
import storage.Storage;
import storage.UndoRedoStackEntry;
import applogger.AppLogger;

public class ScheduleMarker {

	private static final String STRING_WHITESPACE = " ";
	private static final String ERROR_MSG_INVALID_COMMAND = "ERROR! Invalid command format! Please try again!";
	private static final String MARK_DONE_COMMAND = "done";
	private static final String MARK_UNDONE_COMMAND = "undone";
	private static final String ERROR_MSG_ALREADY_DONE = "This Event is already Done!";
	private static final String ERROR_MSG_ALREADY_UNDONE = "This Event is already Undone!";

	private static final char DIGIT_MIN = '0';
	private static final char DIGIT_MAX = '9';
	
	private Storage eventsList;
	
	/**
	 * Constructor for Schedule Marker. Takes in the current LifeShelf storage.
	 * @param eventsList
	 */
	public ScheduleMarker(Storage eventsList) {
		this.eventsList = eventsList;
	}
	
	/**
	 * Reads the user input. If valid, it will call the respective methods to mark or unmark an event.
	 * @param userCommandDetails
	 * @return responseMessage if successful or error message if unsuccessful
	 */
	public String markEvent(String userCommandDetails) {
		AppLogger.log("Decoding Mark Command");
		String[] markCommandDetails = userCommandDetails.split(STRING_WHITESPACE);
		if (markCommandDetails.length != 2) {
			return ERROR_MSG_INVALID_COMMAND;
		}
		if (isInteger(markCommandDetails[0])) {
			String responseMessage;
			switch (markCommandDetails[1]) {
				case MARK_DONE_COMMAND:
					responseMessage = markEventDone(Integer.parseInt(markCommandDetails[0]));
					eventsList.clearRedoStack();
					return responseMessage;
				case MARK_UNDONE_COMMAND:
					responseMessage = markEventUndone(Integer.parseInt(markCommandDetails[0]));
					eventsList.clearRedoStack();
					return responseMessage;
			}
		}
		return ERROR_MSG_INVALID_COMMAND;
	}
	
	/**
	 * Marks an event done by calling ScheduleEvent.markEventDone();
	 * @param eventIndex
	 * @return successMessage or Error Message if not successful.
	 */
	public String markEventDone (int eventIndex) {
		AppLogger.log("Trying to mark Event Done");
		try {
			ScheduleEvent eventToMark = eventsList.getEvent(eventIndex-1);
			if (eventToMark.getIsDone()) {
				return ERROR_MSG_ALREADY_DONE;
			}
			eventsList.getUndoStack().push(new UndoRedoStackEntry(MARK_DONE_COMMAND, eventToMark));
			return eventsList.markEventDone(eventIndex);
		} catch (Exception e) {
			AppLogger.log(e.toString());
			return ERROR_MSG_INVALID_COMMAND;
		}
	}
	
	/**
	 * Marks an event as not done by calling ScheduleEvent.markEventUndone();
	 * @param eventIndex
	 * @return successMessage or Error Message if not successful.
	 */
	public String markEventUndone (int eventIndex) {
		AppLogger.log("Trying to mark Event Not Done");
		try {
			ScheduleEvent eventToMark = eventsList.getEvent(eventIndex-1);
			if (!eventToMark.getIsDone()) {
				return ERROR_MSG_ALREADY_UNDONE;
			}
			eventsList.getUndoStack().push(new UndoRedoStackEntry(MARK_UNDONE_COMMAND, eventToMark));
			return eventsList.markEventUndone(eventIndex);
		} catch (Exception e) {
			AppLogger.log(e.toString());
			return ERROR_MSG_INVALID_COMMAND;
		}
	}
	
	/**
	 * Checks if the input string is an integer
	 * @param stringToCheck
	 * @return true if input string is integer
	 */
	private boolean isInteger(String stringToCheck) {
		for (int i = 0; i < stringToCheck.length(); i ++) {
			if (!isDigit(stringToCheck.charAt(i))) return false;
		}
		return true;
	}
	
	/**
	 * Checks if the character given is a digit.
	 * @param charAt
	 * @return true if char is a digit.
	 */
	private boolean isDigit(char charAt) {
		if ((int)charAt < (int)DIGIT_MIN || (int)charAt > (int)DIGIT_MAX) return false;
		else return true;
	}
}
